/*
//              INTEL CORPORATION PROPRIETARY INFORMATION
//  This software is supplied under the terms of a license  agreement or
//  nondisclosure agreement with Intel Corporation and may not be copied
//  or disclosed except in  accordance  with the terms of that agreement.
//    Copyright (c) 2006-2007 Intel Corporation. All Rights Reserved.
//
*/
#include "umc_defs.h"
#if defined (UMC_ENABLE_DV_VIDEO_ENCODER)

#include "umc_dv_video_encoder.h"
#include "umc_dv_enc_compressor_def.h"
#include "umc_dv_enc_segment_compressor.h"
#include "umc_dv_enc_huffman.h"
#include "umc_dv_enc_block.h"
#include "umc_dv_enc_encode_bit_stream.h"

namespace UMC
{

Ipp16s *TableMaxAmpOnRun;
ENCODE_ELEMENT **EncodeTables;

void DVVideoEncoder::InitHuffmanTables(Ipp8u* HuffmanTablesBuffer)

{
    Ipp8s *lpcWork;
    Ipp32s i;

    Ipp64u pHuffmanTablesBuffer = (Ipp64u) HuffmanTablesBuffer;
    pHuffmanTablesBuffer += 0x0fff;
    Ipp64s mask = -4096;                               //0xfffffffffffff000 is -4096
    pHuffmanTablesBuffer &= mask;                      //pHuffmanTablesBuffer & 0xfffffffffffff000
    lpcWork = (Ipp8s *) pHuffmanTablesBuffer;
    //lpcWork = (Ipp8s *) ((((Ipp64u)HuffmanTablesBuffer) + 0x0fff) & 0xfffffffffffff000);

    TableMaxAmpOnRun = (Ipp16s*)lpcWork;
    TableMaxAmpOnRun[0] = 0xff;//255;
    TableMaxAmpOnRun[1] = 17;
    TableMaxAmpOnRun[2] = 11;
    TableMaxAmpOnRun[3] = 7;
    TableMaxAmpOnRun[4] = 5;
    TableMaxAmpOnRun[5] = 3;
    TableMaxAmpOnRun[6] = 3;
    TableMaxAmpOnRun[7] = 3;
    TableMaxAmpOnRun[8] = 3;
    TableMaxAmpOnRun[9] = 2;
    TableMaxAmpOnRun[10] = 2;
    TableMaxAmpOnRun[11] = 1;
    TableMaxAmpOnRun[12] = 1;
    TableMaxAmpOnRun[13] = 1;
    TableMaxAmpOnRun[14] = 1;
    for (i = 15;i < 63;i++)
        TableMaxAmpOnRun[i] = 0;

    lpcWork += sizeof(TableMaxAmpOnRun[0]) * 64;

    EncodeTables = (ENCODE_ELEMENT**) lpcWork;;

    lpcWork += sizeof(EncodeTables[0]) * 62;

    EncodeTables[0] = (ENCODE_ELEMENT *) lpcWork;    lpcWork += sizeof(ENCODE_ELEMENT) * 256;
    EncodeTables[1] = (ENCODE_ELEMENT *) lpcWork;    lpcWork += sizeof(ENCODE_ELEMENT) * 18;
    EncodeTables[2] = (ENCODE_ELEMENT *) lpcWork;    lpcWork += sizeof(ENCODE_ELEMENT) * 12;
    EncodeTables[3] = (ENCODE_ELEMENT *) lpcWork;    lpcWork += sizeof(ENCODE_ELEMENT) * 8;
    EncodeTables[4] = (ENCODE_ELEMENT *) lpcWork;    lpcWork += sizeof(ENCODE_ELEMENT) * 6;
    EncodeTables[5] = (ENCODE_ELEMENT *) lpcWork;    lpcWork += sizeof(ENCODE_ELEMENT) * 4;
    EncodeTables[6] = (ENCODE_ELEMENT *) lpcWork;    lpcWork += sizeof(ENCODE_ELEMENT) * 4;
    EncodeTables[7] = (ENCODE_ELEMENT *) lpcWork;    lpcWork += sizeof(ENCODE_ELEMENT) * 4;
    EncodeTables[8] = (ENCODE_ELEMENT *) lpcWork;    lpcWork += sizeof(ENCODE_ELEMENT) * 4;
    EncodeTables[9] = (ENCODE_ELEMENT *) lpcWork;    lpcWork += sizeof(ENCODE_ELEMENT) * 3;
    EncodeTables[10] = (ENCODE_ELEMENT *) lpcWork;   lpcWork += sizeof(ENCODE_ELEMENT) * 3;
    EncodeTables[11] = (ENCODE_ELEMENT *) lpcWork;   lpcWork += sizeof(ENCODE_ELEMENT) * 2;
    EncodeTables[12] = (ENCODE_ELEMENT *) lpcWork;   lpcWork += sizeof(ENCODE_ELEMENT) * 2;
    EncodeTables[13] = (ENCODE_ELEMENT *) lpcWork;   lpcWork += sizeof(ENCODE_ELEMENT) * 2;
    EncodeTables[14] = (ENCODE_ELEMENT *) lpcWork;   lpcWork += sizeof(ENCODE_ELEMENT) * 2;
    EncodeTables[15] = (ENCODE_ELEMENT *) lpcWork;   lpcWork += sizeof(ENCODE_ELEMENT) * 1;
    for(i = 16;i < 62;i++)
    {
        EncodeTables[i] = (ENCODE_ELEMENT *) lpcWork;
        lpcWork += sizeof(ENCODE_ELEMENT) * 1;
    }

// [run][amp]
// [~][0]
    EncodeTables[1][0].length = 11;  EncodeTables[1][0].code = 0x07cf;
    EncodeTables[2][0].length = 12;  EncodeTables[2][0].code = 0x0fac;
    EncodeTables[3][0].length = 12;  EncodeTables[3][0].code = 0x0fad;
    EncodeTables[4][0].length = 12;  EncodeTables[4][0].code = 0x0fae;
    EncodeTables[5][0].length = 12;  EncodeTables[5][0].code = 0x0faf;
    EncodeTables[6][0].length = 13;  EncodeTables[6][0].code = 0x1f86;
    for (i = 7;i < 62;i++)
    {
        EncodeTables[i][0].length = 13;
        EncodeTables[i][0].code = EncodeTables[i-1][0].code + 1;
    }

// [0][~]
    EncodeTables[0][0].length = 11; EncodeTables[0][0].code = 0x07ce;
    EncodeTables[0][1].length = 3; EncodeTables[0][1].code = 0x0000;
    EncodeTables[0][2].length = 4; EncodeTables[0][2].code = 0x0004;
    EncodeTables[0][3].length = 5; EncodeTables[0][3].code = 0x0010;
    EncodeTables[0][4].length = 5; EncodeTables[0][4].code = 0x0012;
    EncodeTables[0][5].length = 6; EncodeTables[0][5].code = 0x002c;
    EncodeTables[0][6].length = 6; EncodeTables[0][6].code = 0x002e;
    EncodeTables[0][7].length = 7; EncodeTables[0][7].code = 0x0064;
    EncodeTables[0][8].length = 7; EncodeTables[0][8].code = 0x0066;
    EncodeTables[0][9].length = 8; EncodeTables[0][9].code = 0x00da;
    EncodeTables[0][10].length = 8; EncodeTables[0][10].code = 0x00dc;
    EncodeTables[0][11].length = 8; EncodeTables[0][11].code = 0x00de;
    EncodeTables[0][12].length = 9; EncodeTables[0][12].code = 0x01d4;
    EncodeTables[0][13].length = 9; EncodeTables[0][13].code = 0x01d6;
    EncodeTables[0][14].length = 9; EncodeTables[0][14].code = 0x01d8;
    EncodeTables[0][15].length = 9; EncodeTables[0][15].code = 0x01da;
    EncodeTables[0][16].length = 9; EncodeTables[0][16].code = 0x01dc;
    EncodeTables[0][17].length = 9; EncodeTables[0][17].code = 0x01de;
    EncodeTables[0][18].length = 10; EncodeTables[0][18].code = 0x03d6;
    EncodeTables[0][19].length = 10; EncodeTables[0][19].code = 0x03d8;
    EncodeTables[0][20].length = 10; EncodeTables[0][20].code = 0x03da;
    EncodeTables[0][21].length = 10; EncodeTables[0][21].code = 0x03dc;
    EncodeTables[0][22].length = 10; EncodeTables[0][22].code = 0x03de;
    EncodeTables[0][23].length = 16; EncodeTables[0][23].code = 0xfe2e;
    for (i = 24;i < 256;i++)
    {
        EncodeTables[0][i].length = 16;
        EncodeTables[0][i].code = EncodeTables[0][i-1].code + 0x02;
    }

// [1][~]
    EncodeTables[1][1].length = 5; EncodeTables[1][1].code = 0x000e;
    EncodeTables[1][2].length = 6; EncodeTables[1][2].code = 0x002a;
    EncodeTables[1][3].length = 8; EncodeTables[1][3].code = 0x00d6;
    EncodeTables[1][4].length = 8; EncodeTables[1][4].code = 0x00d8;
    EncodeTables[1][5].length = 9; EncodeTables[1][5].code = 0x01ce;
    EncodeTables[1][6].length = 9; EncodeTables[1][6].code = 0x01d0;
    EncodeTables[1][7].length = 9; EncodeTables[1][7].code = 0x01d2;
    EncodeTables[1][8].length = 10; EncodeTables[1][8].code = 0x03d4;
    EncodeTables[1][9].length = 11; EncodeTables[1][9].code = 0x07c8;
    EncodeTables[1][10].length = 11; EncodeTables[1][10].code = 0x07ca;
    EncodeTables[1][11].length = 11; EncodeTables[1][11].code = 0x07cc;
    EncodeTables[1][12].length = 12; EncodeTables[1][12].code = 0x0fa6;
    EncodeTables[1][13].length = 12; EncodeTables[1][13].code = 0x0fa8;
    EncodeTables[1][14].length = 12; EncodeTables[1][14].code = 0x0faa;
    EncodeTables[1][15].length = 13; EncodeTables[1][15].code = 0x1f7a;
    EncodeTables[1][16].length = 13; EncodeTables[1][16].code = 0x1f7c;
    EncodeTables[1][17].length = 13; EncodeTables[1][17].code = 0x1f7e;

// [2][~]
    EncodeTables[2][1].length = 6; EncodeTables[2][1].code = 0x0028;
    EncodeTables[2][2].length = 8; EncodeTables[2][2].code = 0x00d4;
    EncodeTables[2][3].length = 9; EncodeTables[2][3].code = 0x01cc;
    EncodeTables[2][4].length = 10; EncodeTables[2][4].code = 0x03d0;
    EncodeTables[2][5].length = 10; EncodeTables[2][5].code = 0x03d2;
    EncodeTables[2][6].length = 11; EncodeTables[2][6].code = 0x07c6;
    EncodeTables[2][7].length = 13; EncodeTables[2][7].code = 0x1f70;
    EncodeTables[2][8].length = 13; EncodeTables[2][8].code = 0x1f72;
    EncodeTables[2][9].length = 13; EncodeTables[2][9].code = 0x1f74;
    EncodeTables[2][10].length = 13; EncodeTables[2][10].code = 0x1f76;
    EncodeTables[2][11].length = 13; EncodeTables[2][11].code = 0x1f78;

// [3][~]
    EncodeTables[3][1].length = 7; EncodeTables[3][1].code = 0x0060;
    EncodeTables[3][2].length = 9; EncodeTables[3][2].code = 0x01c8;
    EncodeTables[3][3].length = 10; EncodeTables[3][3].code = 0x03cc;
    EncodeTables[3][4].length = 11; EncodeTables[3][4].code = 0x07c2;
    EncodeTables[3][5].length = 11; EncodeTables[3][5].code = 0x07c4;
    EncodeTables[3][6].length = 12; EncodeTables[3][6].code = 0x0fa4;
    EncodeTables[3][7].length = 13; EncodeTables[3][7].code = 0x1f6e;

// [4][~]
    EncodeTables[4][1].length = 7; EncodeTables[4][1].code = 0x0062;
    EncodeTables[4][2].length = 9; EncodeTables[4][2].code = 0x01ca;
    EncodeTables[4][3].length = 10; EncodeTables[4][3].code = 0x03ce;
    EncodeTables[4][4].length = 12; EncodeTables[4][4].code = 0x0fa2;
    EncodeTables[4][5].length = 13; EncodeTables[4][5].code = 0x1f6c;

// [5][~]
    EncodeTables[5][1].length = 8; EncodeTables[5][1].code = 0x00d0;
    EncodeTables[5][2].length = 10; EncodeTables[5][2].code = 0x03c8;
    EncodeTables[5][3].length = 11; EncodeTables[5][3].code = 0x07c0;

// [6][~]
    EncodeTables[6][1].length = 8; EncodeTables[6][1].code = 0x00d2;
    EncodeTables[6][2].length = 10; EncodeTables[6][2].code = 0x03ca;
    EncodeTables[6][3].length = 12; EncodeTables[6][3].code = 0x0fa0;

// [7][~]
    EncodeTables[7][1].length = 9; EncodeTables[7][1].code = 0x01c0;
    EncodeTables[7][2].length = 13; EncodeTables[7][2].code = 0x1f60;
    EncodeTables[7][3].length = 13; EncodeTables[7][3].code = 0x1f68;

// [8][~]
    EncodeTables[8][1].length = 9; EncodeTables[8][1].code = 0x01c2;
    EncodeTables[8][2].length = 13; EncodeTables[8][2].code = 0x1f62;
    EncodeTables[8][3].length = 13; EncodeTables[8][3].code = 0x1f6a;

// [9][~]
    EncodeTables[9][1].length = 9; EncodeTables[9][1].code = 0x01c4;
    EncodeTables[9][2].length = 13; EncodeTables[9][2].code = 0x1f64;

// [10][~]
    EncodeTables[10][1].length = 9; EncodeTables[10][1].code = 0x01c6;
    EncodeTables[10][2].length = 13; EncodeTables[10][2].code = 0x1f66;

// [~][~]
    EncodeTables[11][1].length = 10; EncodeTables[11][1].code = 0x03c0;
    EncodeTables[12][1].length = 10; EncodeTables[12][1].code = 0x03c2;
    EncodeTables[13][1].length = 10; EncodeTables[13][1].code = 0x03c4;
    EncodeTables[14][1].length = 10; EncodeTables[14][1].code = 0x03c6;

} //void InitHuffmanEnc(void)

void SegmentCompressor::EncodeHuffman(DV_SEGMENT *lpDVSegment)
{
    Ipp32s i, j;
    ENCODE_BIT_STREAM *lpCurStreamE, *lpCurStreamF;
    BLOCK *lpCurBlock;

    lpCurStreamE = m_Streams;
    lpCurBlock = m_VSegment.m_pDCTBlocks;

    //First pass
    for (i = 0;i < 5;i++)
    {
        ENCODE_BIT_STREAM **lpLastStreamE = &(m_MStreamsE[i]);
        ENCODE_BIT_STREAM **lpLastStreamF = &(m_MStreamsF[i]);

        for (j = 0;j < m_nDCTBlocksInMB; j++)
        {
            switch(EncodeBitStream(lpCurStreamE, lpCurBlock))
            {
            case STREAM_OVER:
                *lpLastStreamF = lpCurStreamE;
                lpLastStreamF = &(lpCurStreamE->m_lpNext);
                break;
            case STREAM_NOT_FULL:
                *lpLastStreamE = lpCurStreamE;
                lpLastStreamE = &(lpCurStreamE->m_lpNext);
                break;
            default:
                break;
            }

            lpCurStreamE++;
            lpCurBlock++;
        }

        *lpLastStreamE = NULL;
        *lpLastStreamF = NULL;
    }

    //Second pass
    {
        ENCODE_BIT_STREAM **lpLastStreamE = &(m_VStreamsE);
        ENCODE_BIT_STREAM **lpLastStreamF = &(m_VStreamsF);

        for (i = 0;i < 5;i++)
        {
            lpCurStreamE = m_MStreamsE[i];
            lpCurStreamF = m_MStreamsF[i];

            // decode mb sequences
            while (lpCurStreamE && lpCurStreamF)
            {
                if (STREAM_FULL == AddBits(lpCurStreamE, lpCurStreamF))
                    lpCurStreamE = lpCurStreamE->m_lpNext;
                else lpCurStreamF = lpCurStreamF->m_lpNext;
            }

            // store remain streams
            *lpLastStreamE = lpCurStreamE;
            while (*lpLastStreamE)
                lpLastStreamE = &((*lpLastStreamE)->m_lpNext);

            *lpLastStreamF = lpCurStreamF;
            while (*lpLastStreamF)
                lpLastStreamF = &((*lpLastStreamF)->m_lpNext);
        }

        *lpLastStreamE = NULL;
        *lpLastStreamF = NULL;
    }

    //Third pass
    {
        lpCurStreamE = m_VStreamsE;
        lpCurStreamF = m_VStreamsF;

        while (lpCurStreamE && lpCurStreamF)
        {
            if (STREAM_FULL == AddBits(lpCurStreamE, lpCurStreamF))
                lpCurStreamE = lpCurStreamE->m_lpNext;
            else lpCurStreamF = lpCurStreamF->m_lpNext;
        }
    }

    //Copy encoded video segment
    {
        Ipp8s *lpc, *lpcSrc;

        lpcSrc = (Ipp8s *) m_lpbBitSequences;

        for (i = 0;i < 5;i++)
        {
            lpc = (Ipp8s *) lpDVSegment->m_EncodedMacroBlocks[i].data;

            for (j = 0;j < m_nDCTBlocksInMB; j++)
            {
                memcpy(lpc, lpcSrc, m_DCTBlockLengths[j]);
                lpc += m_DCTBlockLengths[j];
                lpcSrc += 128;
            }
        }
    }
} // void SegmentCompressor::EncodeHuffman()

}//namespace UMC

#endif //(UMC_ENABLE_DV_VIDEO_ENCODER)
